package org.NooLab.randomgraph;

import java.util.ArrayList;

import org.NooLab.itexx.storage.DbUser;
import org.NooLab.randomgraph.components.RGraphFingerPrints;
import org.NooLab.randomgraph.components.RGraphNeighborhood;
import org.NooLab.randomgraph.components.RandomGraphIIntf;
import org.NooLab.randomgraph.components.RandomGraphProcessor;
import org.NooLab.randomgraph.components.TextCleanerIntf;
import org.NooLab.randomgraph.components.TopologyProcessor;
import org.NooLab.randomgraph.components.WordCleanerIntf;
import org.NooLab.randomgraph.properties.RGraphProperties;
import org.NooLab.somquery.SomQueryIntf;
import org.NooLab.structures.randomgraph.ParticledText;
import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.objects.StringedObjects;
import org.NooLab.utilities.strings.StringsUtil;


/**
 * 
 *  
 * 
 * 
 *
 */
public class RandomGraph implements RandomGraphIntf, RandomGraphIIntf{

	RandomGraphFactory rgFactory;
	private RGraphProperties rgProperties;
	private ParticledText pText;

	// pre-processors, should/could be replaceable by plugins...
	// ....................................................
	// remove accents, umlauts
	// simple processing ....................
	// removing special quotation marks, non-ascii stuff
	WordCleanerIntf wordcleaner ;
	TextCleanerIntf textCleaner ;
	SmallContextReplacementIntf smallContextReplacer ; 
	
	DbUser dbUser;
	
	SomQueryIntf somquery;
	// ....................................................
	
	RGraphResultsProvidingEventSinkIntf clientInformer=null ;
	boolean isWaiting=false, proceed=true;
	
	StringsUtil strgutil;
	// protected PluggedCapabilities pcap ;
	
	String fileSource = "" ;
	String inText = "" ;
	
	RGraphFingerPrints rgFingerPrintsHandler ;
	
	/** description of results : filename, length of file, number of words, 
	 *                             */
	RGraphResultDescription rgResults = new RGraphResultDescription();
	private ArrayList<ArrayList<?>> documentsRgraphTable ;
	
	ArrayList<String> headerColumns;
	/** 
	 * we have one row per context, the whole table describes the text
	 * 
	 */
	ArrayList<ArrayList<?>> valuesTable;

	
	
	
	public StringedObjects strobj = new StringedObjects ();
	public DFutils fileutil = new DFutils ();
	PrintLog out = new PrintLog(2,true) ;
	
	
	// ========================================================================
	protected RandomGraph( RandomGraphFactory factory ) throws Exception {
		// 
		rgFactory = factory;
		rgProperties = (RGraphProperties) rgFactory.getRgProperties() ;
		
		rgFactory.setRGraph(this) ;
		
		init() ;
		
		out.setPrefix("[RGraph]") ;
	}
	// ========================================================================

	private void init() throws Exception{
		setDocumentsRgraphTable(new ArrayList<ArrayList<?>> ());
		headerColumns = new ArrayList<String>();  
		
		valuesTable = new ArrayList<ArrayList<?>> ();
		
		
		documentsRgraphTable.add(headerColumns);
		documentsRgraphTable.add(valuesTable) ; // we have one row per context, the whole table describes the text

		// this also cares for the DB
		rgFingerPrintsHandler = new RGraphFingerPrints(rgFactory);
		rgFingerPrintsHandler.init();
		
		clientInformer = rgFactory.clientInformer ;
	}
	
	

	public int setTextString(String text) {	
		int len=-1;
		inText = text;
		
		try{
			
			len = inText.length();
			
		}catch(Exception e){
			len=-7;
		}
		return len;
	}
	
	public void start() {
		// perform... we are already in a dedicated thread through RGraphPrepare...
		
		RGraphNeighborhood topoChunks ;
		RandomGraphProcessor rgProcessor ;
		String tableEnc="" ;
		
		try{
			clientInformer = rgFactory.clientInformer ;
			smallContextReplacer = rgFactory.smallContextReplacer ; // does nothing
			wordcleaner = rgFactory.wordcleaner;  // in WordCunker
			textCleaner = rgFactory.textCleaner ; // in WordCunker
			somquery = rgFactory.somQuery ;       // for creating fingerprint entries,
			                                      // and checking similarities of contexts in renormalization context 
			
			int len = inText.length();
			out.print(2, "starting RandomGraph..., length of input text : "+len) ;
			
			// pcap = new PluggedCapabilities(this); 
			// rgProperties.setPluggedCapabilities(pcap) ;
			
			
			BasicTextProcessor basicProcessor = new BasicTextProcessor(this);
			
			basicProcessor.acquireText( inText );
			// calling chunkers, according to entity (word or sentence)
			// first the sentences, we need this for reasoning about capitals
			// basicProcessor.digestText( RandomGraphIntf._RG_ENTITY_SENTENCE ) ;
			// actually, it can't be separated...
			// word chunking will deliver sentences too
			
			int result = basicProcessor.digestText( RandomGraphIntf._RG_ENTITY_WORD ) ; // is it possible to split the task there ??? 
						 if (result<0){
							 out.printErr(1, "digesting text ... failed!") ;
							 return ;
						 }
			
															out.print(2, "splitting text into entities has been completed...");
			/* now we have objects (in a list) that describe the words, and objects that describe the sentences
			 * further processing may add additional properties
			*/ 
															
			pText = basicProcessor.getParticledText() ;
			// the procs up to here are also useful for stats processing ...
			
			
			// this mechanism is exclusively used for Variants !!! ( PoS, Synonyms, translation ) ...
			// despite small context replacement is similarly organized...
			if (clientInformer!=null){
				out.printErr(3, "RandomGraph (id: "+rgFactory.callingProcessGuid+") about to inform the client about intermediate results (1)...") ;
				informClientAboutResults( 1, pText); // here we can introduce special treatments on the side of the caller !!
			}
			// TODO: o/e and saliency values can be greatly enhanced if a few similar documents from the web are cross-checked
			//       and "externalAbundance" module could serve that, ...yet a query to fingerprint would do it also
			
			
			if (smallContextReplacer != null){
				// this is NOT part of Randomgraph, it is part of Texx, and called by callback
				pText = smallContextReplacer.perform(pText);
			}
			
			basicProcessor.applyWordCleaner(); 
			// this is a simple word cleaner, it acts just on the particles,
			// ensuring that words are words "abc   abc-  ...
			
			
			// from here on, we could have a series of such calculations, 
			// dependent on the requested settings, i.e. various replacements or enrichments based on dictionaries, including SomStore itself
			
			rgProcessor = new RandomGraphProcessor( rgFactory, RandomGraphIntf._RG_ENTITY_WORD ) ;
															out.print(2, "creating random graph elements...") ;
															
			// TODO: this should take the sentences into consideration!!
            //       words left of the beginning are reduced in relevancy  															
			rgProcessor.createRawRandomGraphs(pText);
													
			// from all the entries in particled text (relative to the selected entity), we create a table 
			// TODO: we have to set the type of results in the results description !!
			tableEnc = rgProcessor.createFinalRandomGraphOutputVector( RandomGraphIntf._RG_ENTITY_WORD);

			
			// the results has to comprise additional info: which word, indexes (word, sentence, char, paragraph)
			// this may be fetched explicitly by the calling instance (method provided by the interface)
			rgResults = createResultDescription();
			
			// this applies random projection to the matrix fpm (for efficiency reasons), and 
			// then it concatenates it into a 1d vector 
			if (rgProperties.isCreateSentenceLevelContexts()){
				// the "same" game for sentences, would need a plugin module, since it needs
				// experience and transposition by renormalization (intrinsic measurement) 
				// this would create a second table that we would have to normalize
				// to the same number of columns...
			}

			
			// checking whether multidigest closes
			rgProcessor.close();
			rgFactory.rgDataBase.close();
															out.print(2, "...done") ;
			rgFactory.setIsFinished(true) ;
			
			// the factory will be closed from the outside
			
		}catch(Exception e){
			e.printStackTrace();
		}
		
		pText.clear();
		pText=null;
		out.delay(10);
		System.gc();
	}


	
	private void informClientAboutResults(int type, ParticledText ptext) throws InterruptedException {
		 
		int z=0, waitperiod=100;
		int response = 0;
		
		
		proceed=false;
		 
		while ((z<waitperiod) && (proceed==false)){
			if (z == 0){
				// in the first loop: send the announcement and get the response
				response = clientInformer.setResultsAvailable( (RandomGraphIntf)this,type,ptext);
			}
		
			
			z++ ;
			if (response>1){
				(new ClientInformerListener( response)).waitForResponse();
				while (proceed==false){
					out.delay(2);
				}
			}
			out.delay(10);
		}
		
	}
	
	class ClientInformerListener implements Runnable{
		int waitperiod = 0 ;
		Thread cilThrd;
		
		public ClientInformerListener(int duration){
			waitperiod  = duration ;
			cilThrd = new Thread(this,"cilThrd"); 
		}

		public void waitForResponse() {
			
			cilThrd.start() ;
		}

		private void waitfor(){
			int r = -1;
			out.printErr(4, "RG: ClientInformerListener is waiting...");
			while ((r<0) && (isWaiting)){
				r = clientInformer.getResponseValue();
				out.delay(5) ;
			}
			proceed = true;
			out.printErr(4, "RandomGraph (id: "+rgFactory.callingProcessGuid+"): "+
					        "ClientInformerListener is proceeding...");
		}
		
		@Override
		public void run() {
			isWaiting=true;
			waitfor();
		}
		
	}
	
	public WordCleanerIntf getWordcleaner() {
		return wordcleaner;
	}

	public void setWordcleaner(WordCleanerIntf wordcleaner) {
		this.wordcleaner = wordcleaner;
	}

	private RGraphResultDescription createResultDescription() {
		RGraphResultDescription rgResults = new RGraphResultDescription();
		
		rgResults.typeOfResults = RandomGraphIntf._RG_RESULTS_FULLTABLE ;
		
		
		return rgResults;
	}
	
	
	public PrintLog getOut() {
		return out;
	}

	public String getInText() {
		return inText;
	}

	public int setInText(String inText) {
		return setTextString( inText );
	}

	public ArrayList<ArrayList<?>> getResults() {
		return documentsRgraphTable;
	}
	 

	public RGraphProperties getRgProperties() {
		return rgProperties;
	}

	@Override
	public RandomGraph getInstanceReference() {
		return this;
	}

	public RandomGraphFactory getRgFactory() {
		return rgFactory;
	}

	public RGraphFingerPrints getRgFingerPrintsHandler() {
		return rgFingerPrintsHandler;
	}

	public void setDocumentsRgraphTable(ArrayList<ArrayList<?>> doctable) {
		documentsRgraphTable = doctable;
	}

	public ArrayList<ArrayList<?>> getDocumentsRgraphTable() {
		return documentsRgraphTable;
	}

	public RGraphResultDescription getRgResults() {
		return rgResults;
	}

	public DbUser getDbUser() {
		return dbUser;
	}

	public void setDbUser(DbUser dbUser) {
		this.dbUser = dbUser;
	}
	
	

	 	
}
